package org.linloong.modules.apis.ai.service.impl;

import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.linloong.config.ai.DifyModelManager;
import org.linloong.config.ai.MultiDifyConfig;
import org.linloong.core.result.Result;
import org.linloong.modules.apis.ai.dto.*;
import org.linloong.modules.apis.ai.service.DifyService;
import org.linloong.utils.HutoolExcelCsvUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.codec.json.Jackson2JsonDecoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.io.IOException;
import java.time.Duration;
import java.util.*;


/**
 * Dify 服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DifyServiceImpl implements DifyService {
    
    private final DifyModelManager difyModelManager;

    private final static String DEFAULT_MODEL = "sydyznt";

    public Mono<ChatResponse> chat(ChatRequest request) {
        String modelName = request.getModel() != null ? request.getModel() : DEFAULT_MODEL;
        log.info("使用模型 {} 发送聊天请求: {}", modelName, request.getMessage());

        WebClient webClient = difyModelManager.getWebClient(modelName);
        MultiDifyConfig.ModelConfig config = difyModelManager.getModelConfig(modelName);

        DifyMessageRequest difyRequest = buildDifyRequest(request, config);

        return webClient.post()
                .uri("/chat-messages")
                .bodyValue(difyRequest)
                .retrieve()
                .bodyToMono(DifyMessageResponse.class)
                .timeout(Duration.ofMillis(config.getReadTimeout()))
                .map(this::convertToChatResponse)
                .onErrorResume(this::handleError);
    }
    
    @Override
    public ChatResponse chatSync(ChatRequest request) {
        return chat(request)
                .timeout(Duration.ofMillis(60000))
                .onErrorResume(error -> {
                    log.error("同步聊天请求失败", error);
                    ChatResponse response = new ChatResponse();
                    response.setSuccess(false);
                    response.setError("聊天请求失败: " + error.getMessage());
                    return Mono.just(response);
                })
                .block();
    }

    @Override
    public Flux<String> chatStream(ChatRequest request) {
        if (org.apache.commons.lang3.StringUtils.isBlank(request.getMessage())) {
            request.setMessage("请给我一个方案！");
        }
        String modelName = request.getModel() != null ? request.getModel() : DEFAULT_MODEL;
        log.info("使用模型 {} 发送流式聊天请求: {}", modelName, request.getMessage());

        WebClient webClient = difyModelManager.getWebClient(modelName);
        MultiDifyConfig.ModelConfig config = difyModelManager.getModelConfig(modelName);

        DifyMessageRequest difyRequest = buildDifyRequest(request, config);

        log.info("请求URL: {}", config.getRequestUrl());
        log.info("请求参数: {}", JSONUtil.toJsonStr(difyRequest));
        return webClient.post()
                .uri(config.getRequestUrl())
                .bodyValue(difyRequest)
                .accept(MediaType.TEXT_EVENT_STREAM)
                .retrieve()
                .bodyToFlux(String.class)
                .timeout(Duration.ofMillis(config.getReadTimeout()))
                .onErrorResume(error -> {
                    log.error("流式请求失败", error);
                    String errorMsg = "data: {\"event\":\"error\",\"error\":\"" + error.getMessage().replace("\"", "\\\"") + "\"}";
                    return Flux.just(errorMsg);
                });
    }

    /**
     * 构建 Dify 请求对象
     */

    private DifyMessageRequest buildDifyRequest(ChatRequest request, MultiDifyConfig.ModelConfig config) {
        DifyMessageRequest difyRequest = new DifyMessageRequest();
        difyRequest.setQuery(request.getMessage());
//        difyRequest.setResponseMode("blocking");
        difyRequest.setUser(StringUtils.hasText(request.getUserId()) ?
                request.getUserId() : config.getDefaultUser());

        if (StringUtils.hasText(request.getConversationId())) {
            difyRequest.setConversationId(request.getConversationId());
        }

        // 构建 inputs 参数
        Map<String, Object> inputs = buildInputsFromRequest(request);
        difyRequest.setInputs(inputs);

        difyRequest.setResponseMode("streaming");
        return difyRequest;
    }
    /**
     * 根据请求构建输入参数
     * @param request 聊天请求
     * @return 输入参数映射
     */
    private Map<String, Object> buildInputsFromRequest(ChatRequest request) {
        Map<String, Object> inputs = new HashMap<>();

        // 如果存在文件ID，则构建文件相关输入参数
        Optional.ofNullable(request.getFileId())
                .filter(StringUtils::hasText)
                .ifPresent(fileId -> {
                    inputs.put("input_csv", createFileInputConfig(fileId));
                });
        Optional.ofNullable(request.getVisualizationMode())
                .filter(StringUtils::hasText)
                .ifPresent(fileId -> {
                    inputs.put("visualization_mode", request.getVisualizationMode());
                });
        Optional.ofNullable(request.getModelName())
                .filter(StringUtils::hasText)
                .ifPresent(fileId -> {
                    inputs.put("model_name", request.getModelName());
                });

        // 构建 input_data 参数
        Map<String, Object> inputData = new HashMap<>();
        
        // 添加判断逻辑，有值了传值
        Optional.ofNullable(request.getEcoWeight())
                .ifPresent(value -> inputData.put("eco_weight", value));
                
        Optional.ofNullable(request.getEconomicWeight())
                .ifPresent(value -> inputData.put("economic_weight", value));
                
        Optional.ofNullable(request.getTemperature())
                .ifPresent(value -> inputData.put("temperature", value));
                
        Optional.ofNullable(request.getPrecipitation())
                .ifPresent(value -> inputData.put("precipitation", value));
                
        Optional.ofNullable(request.getHumidity())
                .ifPresent(value -> inputData.put("humidity", value));
                
        Optional.ofNullable(request.getSunshineDuration())
                .ifPresent(value -> inputData.put("sunshine_duration", value));
                
        Optional.ofNullable(request.getSoilMoisture())
                .ifPresent(value -> inputData.put("soil_moisture", value));
                
        Optional.ofNullable(request.getNutrientConcentration())
                .ifPresent(value -> inputData.put("nutrient_concentration", value));
                
        Optional.ofNullable(request.getPestMonitoring())
                .ifPresent(value -> inputData.put("pest_monitoring", value));
                
        Optional.ofNullable(request.getTreeHeight())
                .ifPresent(value -> inputData.put("tree_height", value));
                
        Optional.ofNullable(request.getDbh())
                .ifPresent(value -> inputData.put("DBH", value));
                
        Optional.ofNullable(request.getGerminationDate())
                .filter(StringUtils::hasText)
                .ifPresent(value -> inputData.put("germination_date", value));
                
        Optional.ofNullable(request.getDefoliationDate())
                .filter(StringUtils::hasText)
                .ifPresent(value -> inputData.put("defoliation_date", value));
                
        Optional.ofNullable(request.getFloweringDate())
                .filter(StringUtils::hasText)
                .ifPresent(value -> inputData.put("flowering_date", value));
        
        // 确保 input_data 始终是一个空的 Map 而不是 null
        inputs.put("input_data", inputData.isEmpty() ? "{}" : JSONUtil.parse(inputData).toString());

        // 如果存在参数信息，则构建文件相关输入参数
        Optional.ofNullable(request.getParameters())
                .filter(StringUtils::hasText)
                .ifPresent(parameters -> {
                    inputs.put("parameters",request.getParameters());
                });
                
        return inputs;
    }
    /**
     * 创建文件输入配置
     * @param fileId 文件ID
     * @return 文件输入配置映射
     */
    private Map<String, Object> createFileInputConfig(String fileId) {
        return Map.of(
                "type", "document",
                "transfer_method", "local_file",
                "url", "",
                "upload_file_id", fileId
        );
    }
    
    /**
     * 转换 Dify 响应为聊天响应
     */
    private ChatResponse convertToChatResponse(DifyMessageResponse difyResponse) {
        ChatResponse response = new ChatResponse();
        response.setMessageId(difyResponse.getId());
        response.setAnswer(difyResponse.getAnswer());
        response.setConversationId(difyResponse.getConversationId());
        response.setCreatedAt(difyResponse.getCreatedAt());
        response.setSuccess(true);
        
        // 设置使用情况信息
        if (difyResponse.getMetadata() != null && difyResponse.getMetadata().getUsage() != null) {
            DifyMessageResponse.Usage usage = difyResponse.getMetadata().getUsage();
            response.setTotalTokens(usage.getTotalTokens());
            response.setLatency(usage.getLatency());
        }
        
        return response;
    }
    
    /**
     * 错误处理
     */
    private Mono<ChatResponse> handleError(Throwable error) {
        log.error("Dify API 调用失败", error);
        
        ChatResponse response = new ChatResponse();
        response.setSuccess(false);
        
        if (error instanceof WebClientResponseException webClientException) {
            String errorMsg = "API 调用失败，状态码: " + webClientException.getStatusCode() + 
                    ", 错误信息: " + webClientException.getResponseBodyAsString();
            response.setError(errorMsg);
        } else {
            response.setError("网络请求失败: " + error.getMessage());
        }
        
        return Mono.just(response);
    }
    @Override
    public FileUploadResponse uploadFile(FileUploadRequest request) {
        List<FileFieldDTO> list = new ArrayList<>();
        try {
            if(request.getTypeValid() == 0){
                list = HutoolExcelCsvUtil.readAndCheckHeader(request.getFile(), FileFieldDTO.class);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        try {
            String modelName = request.getModel() != null ? request.getModel() : DEFAULT_MODEL;
            MultiDifyConfig.ModelConfig config = difyModelManager.getModelConfig(modelName);
            FileUploadResponse response = difyModelManager.getFileWebClient(modelName)
                    .post()
                    .uri("/files/upload")
                    .body(BodyInserters.fromMultipartData("file", request.getFile().getResource())
                            .with("user", StringUtils.hasText(request.getUserId()) ?
                                    request.getUserId() : config.getDefaultUser()))
                    .retrieve()
                    .bodyToMono(FileUploadResponse.class)
                    .block();
            response.setData(list);
            return response;
        } catch (Exception e) {
            throw new RuntimeException("文件上传失败", e);
        }
    }

    @Value("${dify.models.faksh.api-key}")
    private String apiKey;
    @Value("${dify.models.faksh.base-url}")
    private String url;

    @Override
    public Result<String> getEchartData(String converstionId) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
        // 允许解析包含转义 Unicode 的字符串
        objectMapper.configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true);

        WebClient webClient = WebClient.builder()
                .baseUrl(url + "/conversations/" + converstionId + "/variables?user=default-user")
                .codecs(configurer -> {
                    configurer.defaultCodecs().maxInMemorySize(100 * 1024 * 1024);
                    configurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(objectMapper));
                })
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                .defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer " + apiKey)
                .build();

        // 获取原始响应字符串
        String rawResponse = webClient.get()
                .retrieve()
                .bodyToMono(String.class)
                .block();

        // 第一次解析：解析外层 JSON，拿到 data 数组
        JsonNode outerNode = objectMapper.readTree(rawResponse);
        JsonNode dataArray = outerNode.get("data");

        if (dataArray != null && dataArray.isArray()) {
            for (JsonNode item : dataArray) {
                if ("echart_data".equals(item.get("name").asText())) {
                    // 获取 value 字段 —— 它是一个 JSON 字符串（被转义过）
                    String innerJsonStr = item.get("value").asText();

                    // 第二次解析：解析内层 JSON（这才是真正的数据）
                    JsonNode innerNode = objectMapper.readTree(innerJsonStr);

                    // 返回解析后的 JsonNode（或转为 Map）
                    return Result.success(objectMapper.writeValueAsString(innerNode));
                }
            }
        }

        return Result.fail("未找到 echart_data");
    }

}